package com.matace.keychain.core.dataBaseBasic;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

// 引入之前定义的常量类
import com.matace.keychain.core.dataBaseBasic.DatabaseConstants;

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final String TAG = "DatabaseHelper";

    // 使用 DatabaseConstants 中定义的数据库名和版本号
    // 如果没有单独的常量类，则在此处定义：
    private static final String DATABASE_NAME = DatabaseConstants.DATABASE_NAME;
    private static final int DATABASE_VERSION = DatabaseConstants.DATABASE_VERSION;

    // ==================== 单例模式实现 ====================
    // 推荐使用单例模式来管理 SQLiteOpenHelper 实例，以避免资源泄露和并发问题。

    private static DatabaseHelper instance;

    // 私有构造函数，确保只能通过 getInstance() 方法获取实例
    private DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        Log.d(TAG, "DatabaseHelper constructor called.");
    }

    /**
     * 获取 DatabaseHelper 的单例实例
     * @param context 应用上下文 (推荐传入 ApplicationContext 以避免 Activity 内存泄漏)
     * @return DatabaseHelper 的单例实例
     */
    public static synchronized DatabaseHelper getInstance(Context context) {
        if (instance == null) {
            // 使用 application context 来防止 activity context 的内存泄漏
            instance = new DatabaseHelper(context.getApplicationContext());
            Log.d(TAG, "DatabaseHelper instance created.");
        }
        return instance;
    }

    // ==================== 数据库生命周期方法 ====================

    /**
     * 数据库首次创建时调用。
     * 在这里创建所有表格。
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG, "onCreate: Creating database tables...");
        try {
            // 执行创建用户表的 SQL 语句
            db.execSQL(DatabaseConstants.SQL_CREATE_USERS_TABLE);
            // 如果有其他表，在这里添加创建它们的 SQL 语句
            // db.execSQL(DatabaseConstants.SQL_CREATE_PRODUCTS_TABLE);
            Log.d(TAG, "onCreate: Tables created successfully.");
        } catch (SQLException e) {
            Log.e(TAG, "onCreate: Error creating tables: " + e.getMessage());
        }
    }

    /**
     * 数据库版本号发生变化时调用。
     * 在这里处理数据库架构的升级和降级。
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG, "onUpgrade: Upgrading database from version " + oldVersion + " to " + newVersion);
        // 简单处理：删除旧表并重新创建。
        // !!! 在实际应用中，应谨慎处理数据库升级，通常需要进行数据迁移，
        // 而不是简单地删除所有表，以免丢失用户数据。
        try {
            db.execSQL("DROP TABLE IF EXISTS " + DatabaseConstants.TABLE_USERS);
            // 删除其他旧表
            // db.execSQL("DROP TABLE IF EXISTS " + DatabaseConstants.TABLE_PRODUCTS);
            onCreate(db); // 重新创建所有表
            Log.d(TAG, "onUpgrade: Database upgraded successfully.");
        } catch (SQLException e) {
            Log.e(TAG, "onUpgrade: Error upgrading database: " + e.getMessage());
        }
    }

    /**
     * 数据库打开时调用，通常在 Android 9 (Pie) 及更高版本中，
     * 如果启用外键约束，在这里设置。
     */
    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        // 启用外键约束 (如果你的数据库设计中使用了外键)
        // db.execSQL("PRAGMA foreign_keys=ON;");
        Log.d(TAG, "onOpen: Database opened.");
    }

    // ==================== 通用 CRUD 操作方法 ====================

    /**
     * 通用插入数据方法。
     * @param tableName 要插入数据的表名。
     * @param values 包含键值对的 ContentValues 对象，键是列名，值是要插入的数据。
     * @return 插入成功时返回新行的 Row ID，如果插入失败则返回 -1。
     */
    public long insertData(String tableName, ContentValues values) {
        SQLiteDatabase db = null;
        long newRowId = -1;
        try {
            db = this.getWritableDatabase(); // 获取可写数据库实例
            newRowId = db.insert(tableName, null, values); // 执行插入操作
            if (newRowId == -1) {
                Log.e(TAG, "insertData: Failed to insert row into " + tableName + ". Values: " + values.toString());
            } else {
                Log.d(TAG, "insertData: Row inserted into " + tableName + " with ID: " + newRowId);
            }
        } catch (SQLException e) {
            Log.e(TAG, "insertData: Error inserting data into " + tableName + ": " + e.getMessage());
        } finally {
            // 单例模式下，通常不在此处关闭数据库连接，由 Helper 自身管理生命周期
            // 如果 db 是方法内部创建的临时对象，则需要关闭
        }
        return newRowId;
    }

    /**
     * 通用查询数据方法。
     * @param tableName 要查询的表名。
     * @param columns 要返回的列名数组，如果为 null，则返回所有列。
     * @param selection WHERE 子句 (例如 "column = ?")。
     * @param selectionArgs selection 子句中的参数值。
     * @param groupBy GROUP BY 子句。
     * @param having HAVING 子句。
     * @param orderBy ORDER BY 子句。
     * @return 包含查询结果的 Cursor 对象。如果查询失败则返回 null。
     * !!! 调用者在使用完 Cursor 后必须负责关闭它，以避免内存泄漏。
     */
    public Cursor queryData(String tableName, String[] columns, String selection,
                            String[] selectionArgs, String groupBy, String having, String orderBy) {
        SQLiteDatabase db = null;
        Cursor cursor = null;
        try {
            db = this.getReadableDatabase(); // 获取可读数据库实例
            cursor = db.query(tableName, columns, selection, selectionArgs,
                    groupBy, having, orderBy); // 执行查询操作

            if (cursor != null) {
                Log.d(TAG, "queryData: Queried " + cursor.getCount() + " rows from " + tableName);
            } else {
                Log.d(TAG, "queryData: Query returned null for " + tableName);
            }
        } catch (SQLException e) {
            Log.e(TAG, "queryData: Error querying data from " + tableName + ": " + e.getMessage());
            cursor = null; // 确保在出错时返回 null
        }
        return cursor; // 记住：在调用代码中务必关闭 Cursor！
    }

    /**
     * 通用更新数据方法。
     * @param tableName 要更新的表名。
     * @param values 包含要更新的列名和新值的 ContentValues 对象。
     * @param selection WHERE 子句 (例如 "column = ?")。
     * @param selectionArgs selection 子句中的参数值。
     * @return 受影响的行数，如果更新失败则返回 -1。
     */
    public int updateData(String tableName, ContentValues values, String selection, String[] selectionArgs) {
        SQLiteDatabase db = null;
        int rowsAffected = -1;
        try {
            db = this.getWritableDatabase(); // 获取可写数据库实例
            rowsAffected = db.update(tableName, values, selection, selectionArgs); // 执行更新操作
            if (rowsAffected > 0) {
                Log.d(TAG, "updateData: Updated " + rowsAffected + " rows in " + tableName);
            } else {
                Log.d(TAG, "updateData: No rows updated in " + tableName);
            }
        } catch (SQLException e) {
            Log.e(TAG, "updateData: Error updating data in " + tableName + ": " + e.getMessage());
        } finally {
            // db.close(); // 单例模式下，通常不在此处关闭
        }
        return rowsAffected;
    }

    /**
     * 通用删除数据方法。
     * @param tableName 要删除数据的表名。
     * @param selection WHERE 子句 (例如 "column = ?")。
     * @param selectionArgs selection 子句中的参数值。
     * @return 被删除的行数，如果删除失败则返回 -1。
     */
    public int deleteData(String tableName, String selection, String[] selectionArgs) {
        SQLiteDatabase db = null;
        int rowsDeleted = -1;
        try {
            db = this.getWritableDatabase(); // 获取可写数据库实例
            rowsDeleted = db.delete(tableName, selection, selectionArgs); // 执行删除操作
            if (rowsDeleted > 0) {
                Log.d(TAG, "deleteData: Deleted " + rowsDeleted + " rows from " + tableName);
            } else {
                Log.d(TAG, "deleteData: No rows deleted from " + tableName);
            }
        } catch (SQLException e) {
            Log.e(TAG, "deleteData: Error deleting data from " + tableName + ": " + e.getMessage());
        } finally {
            // db.close(); // 单例模式下，通常不在此处关闭
        }
        return rowsDeleted;
    }

    // ==================== 辅助方法（可选） ====================

    /**
     * 获取一个可写的 SQLiteDatabase 实例。
     * (推荐通过 DatabaseHelper.getInstance() 来获取 helper 对象，再调用此方法)
     */
    public SQLiteDatabase getWritableDb() {
        return this.getWritableDatabase();
    }

    /**
     * 获取一个可读的 SQLiteDatabase 实例。
     * (推荐通过 DatabaseHelper.getInstance() 来获取 helper 对象，再调用此方法)
     */
    public SQLiteDatabase getReadableDb() {
        return this.getReadableDatabase();
    }

    /**
     * 关闭数据库连接。
     * 建议在应用退出或不再需要数据库时调用。
     */
    public void closeDatabase() {
        if (instance != null) {
            instance.close();
            instance = null; // 将单例实例置空，以便下次可以重新创建
            Log.d(TAG, "DatabaseHelper instance closed.");
        }
    }
}
